﻿// socketc.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include<WinSock2.h>
using namespace std;
#pragma comment(lib,"ws2_32.lib")

const int Buffsize = 1024;
int download() 
{
	//第一步初始化socket
	WSADATA WsData;//WSADATA，一种数据结构。这个结构被用来存储被WSAStartup函数调用后返回的Windows Sockets数据。它包含Winsock.dll执行的数据。
	//socket编程中：声明调用不同的Winsock版本。例如MAKEWORD(2, 2)就是调用2.2版
	if (WSAStartup(MAKEWORD(2,2),&WsData))//WSAStartup，即WSA(Windows Sockets Asynchronous，Windows异步套接字)的启动命令
	{
		cout << "socket初始化失败" << endl;
		return 0;
	}
	/*--------------------------------------------------------------------*/
	//创建并绑定ip地址和端口
	SOCKET socketid;//生成的socket的值
	SOCKADDR_IN addr;//存放socket IP地址和端口
	if (-1==(socketid=socket(AF_INET,SOCK_STREAM,0)))
	{
		cout << "socket创建失败" << endl;
		return 0;
	}
	addr.sin_addr.S_un.S_addr = inet_addr("101.227.131.64");
	addr.sin_family = AF_INET;
	addr.sin_port = htons(80);
	
	
	//开始链接
	if (SOCKET_ERROR==connect(socketid,(SOCKADDR *)&addr,sizeof(addr)))
	{
		cout << "连接服务器失败" << endl;
		closesocket(socketid);
		WSACleanup();
		return 0;
	}
	//初始化请求数据
	char* pReqHead = new char[Buffsize];
	pReqHead[0] = '\0';
	//请求行
	strcat(pReqHead,"GET");
	strcat(pReqHead, "/original/im/QQ9.1.7.25980.exe");//https://dl.softmgr.qq.com/original/im/QQ9.1.7.25980.exe
	strcat(pReqHead, "HTTP/1.1\r\n");

	//报头
	strcat(pReqHead, "host:");
	strcat(pReqHead, "dl.softmgr.qq.com");
	strcat(pReqHead, "\r\nConnect:Cloe\r\n\r\n");
	cout<<pReqHead<<endl;

	//开始发送请求
	//strlen所作的仅仅是一个计数器的工作，它从内存的某个位置（可以是字符串开头，中间某个位置，甚至是某个不确定的内存区域）开始扫描，直到碰到第一个字符串结束符'\0'为止，然后返回计数器值(长度不包含'\0')。
	if (SOCKET_ERROR==send(socketid,pReqHead,strlen(pReqHead),0))
	{
		cout << "请求发送失败" << endl;
		closesocket(socketid);
		WSACleanup();
		delete pReqHead;
		return 0;
	}
	delete pReqHead;
	
	//准备接收文件
	FILE* fp, * fRes;
	errno_t err;
	err = fopen_s(&fp, "d:/hahah.exe", "a");
	errno_t err1;
	err1 = fopen_s(&fRes, "d:/hahah.txt", "a");
	/*
	fp = fopen_s("d:/hahah.exe", "wb+");
	fRes = fopen_s("d:/hahaha.txt", "wb+");
	*/
	if (NULL==fp)
	{
		cout<<"创建文件失败"<<endl;
		closesocket(socketid);
		WSACleanup();
		return 0;
	}





	//定义缓冲区，准备接收数据
	char* buff = (char*)malloc(Buffsize * sizeof(char));
	memset(buff, '\0', Buffsize);
	int iRec = 0;
	bool bStart = false;
	//开始接收数据
	//recv使用MSG_DONTWAIT，在发现多次接收长度小于等于0时，中断接收返回。
	while ((iRec = recv(socketid, buff, Buffsize, 0)) > 0)
	{
		if (bStart)
		{
			fwrite(buff, iRec, 1, fp);
		}
		else 
		{
			char* pEnd = strstr(buff,"\r\n\r\n");
			if (pEnd==NULL)
			{
				fwrite(buff, iRec, 1, fp);
				fwrite(buff, iRec, 1, fRes);
			}
			else
			{
				bStart = true;
				int iHead = pEnd + 4 - buff;
				fwrite(pEnd + 4, iRec - (iHead), 1, fp);
				fwrite(buff, iHead, 1, fRes);
			}
		}
	}
	fclose(fp);
	fclose(fRes);
	free(buff);
	closesocket(socketid);
	WSACleanup();
	cout<<"下载结束"<<endl;
	return 1;

}

int main()
{
	

	if (download()==0)
	{
		cout<<"下载失败"<<endl;
	}
	else
	{
		cout<<"下载成功"<<endl;
	}
	system("pause");
	return 0;
	
}

// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单

// 入门使用技巧: 
//   1. 使用解决方案资源管理器窗口添加/管理文件
//   2. 使用团队资源管理器窗口连接到源代码管理
//   3. 使用输出窗口查看生成输出和其他消息
//   4. 使用错误列表窗口查看错误
//   5. 转到“项目”>“添加新项”以创建新的代码文件，或转到“项目”>“添加现有项”以将现有代码文件添加到项目
//   6. 将来，若要再次打开此项目，请转到“文件”>“打开”>“项目”并选择 .sln 文件
